"""
ftp 文件服务器
并发网络功能训练
"""
import os
from socket import *
from threading import Thread
from time import sleep

HOST = '0.0.0.0'
PORT = 8080
ADDR = (HOST, PORT)
# 文件夹路径
FTP = 'Dir/'


# 将客户端请求功能封装为类
class FTPServer:
    def __init__(self, connfd, FTP_PATH):
        self.connfd = connfd
        self.path = FTP_PATH

    def do_list(self):
        # 获取文件列表
        files = os.listdir(self.path)
        if not files:
            self.connfd.send('该文件类别为空'.encode())
            return
        else:
            self.connfd.send(b'OK')
            sleep(0.1)
        fs = ''
        for file in files:
            # 不是隐藏文件且为普通文件
            if file[0] != '.' and os.path.isfile(self.path + file):
                # 连续发送会出现粘包问题（粘包，即多个发送请求，接收方一次性接收消息）
                # sleep(0.1)
                # self.connfd.send(file.encode())
                fs += file + '\n'
        # self.connfd.send(b'##')
        self.connfd.send(fs.encode())

    def do_get(self, filename):
        print('下载文件', filename)
        try:
            fd = open(self.path + filename, 'rb')
        except Exception:
            self.connfd.send('文件不存在'.encode())
            return
        else:
            self.connfd.send(b'OK')
            # 防止粘包
            sleep(0.1)
        while True:
            data = fd.read(1024)
            if not data:
                # 防止粘包
                sleep(0.1)
                self.connfd.send(b'##')
                break
            self.connfd.send(data)

    def do_put(self,filename):
        if os.path.exists(self.path+filename):
            self.connfd.send('该文件已存在'.encode())
            return
        self.connfd.send(b'OK')
        with open(self.path+filename,'wb') as fd:
            while True:
                data = self.connfd.recv(1024)
                if data == b'##':
                    break
                fd.write(data)



# 客户端请求
def handle(connfd):
    # 选择文件夹
    cls = connfd.recv(1024).decode()
    FTP_PATH = FTP + cls + '/'
    ftp = FTPServer(connfd, FTP_PATH)
    while True:
        # 接收客户端请求命令
        data = connfd.recv(1024).decode()
        # 如果客户端断开返回data为空
        if not data or data[0] == 'Q':
            return
        elif data[0] == 'L':
            ftp.do_list()
        elif data[0] == 'G':
            filename = data.split(' ')[-1]
            ftp.do_get(filename)
        elif data[0] == 'P':
            filename = data.split(' ')[-1]
            ftp.do_put(filename)


# 网络搭建
def main():
    sockfd = socket()
    sockfd.setsockopt(SOL_SOCKET, SO_REUSEADDR, 1)
    sockfd.bind(ADDR)
    sockfd.listen(5)
    print('Listent the port 8080..')
    while True:
        try:
            connfd, addr = sockfd.accept()
        except KeyboardInterrupt:
            print('退出服务程序')
            return
        except Exception as e:
            print(e)
            continue
        print('链接的客户端:', addr)

        client = Thread(target=handle, args=(connfd,))
        client.setDaemon(True)
        client.start()


if __name__ == "__main__":
    main()
